package pers.yurwisher.rubick.oauth2.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.code.RandomValueAuthorizationCodeServices;
import pers.yurwisher.rubick.common.serializer.CustomGenericFastJsonRedisSerializer;
import pers.yurwisher.rubick.oauth2.common.CacheConstant;

import java.util.Objects;

/**
 * redis授权码模式授权码服务-操作授权码生成、存储、删除
 * @author yq 2021年4月15日 20:28:46
 */
@Slf4j
public class RedisAuthorizationCodeServices extends RandomValueAuthorizationCodeServices {

    /**
     * 授权码有效时长
     */
    private final long ttlSeconds;
    private final RedisTemplate<String, Object> redisTemplate;
    private final RedisSerializer<String> keySerializer;
    private final CustomGenericFastJsonRedisSerializer valueSerializer;

    public RedisAuthorizationCodeServices(RedisTemplate<String, Object> redisTemplate, long ttlSeconds) {
        this.redisTemplate = redisTemplate;
        this.ttlSeconds = ttlSeconds;
        //缓存redis的Serializer 参照RedisConfig中配置
        this.valueSerializer = (CustomGenericFastJsonRedisSerializer) redisTemplate.getDefaultSerializer();
        this.keySerializer = (StringRedisSerializer) redisTemplate.getKeySerializer();
    }

    /**
     * 将随机生成的授权码存到redis中
     *
     * @param code 授权码
     * @param authentication authentication
     * @return void
     */
    @Override
    protected void store(String code, OAuth2Authentication authentication) {
        log.info("随机授权码: [{}]", code);
        byte[] serializedKey = keySerializer.serialize(CacheConstant.Strings.AUTHORIZATION_CODE_PREFIX + code);
        byte[] serializedAuthentication = valueSerializer.serialize(authentication);
        redisTemplate.execute(conn -> {
            conn.set(Objects.requireNonNull(serializedKey), Objects.requireNonNull(serializedAuthentication));
            conn.expire(Objects.requireNonNull(serializedKey), ttlSeconds);
            return null;
        }, true, true);
    }

    /**
     * 取出授权码并删除授权码
     *
     * @param code 授权码
     * @return org.springframework.security.oauth2.provider.OAuth2Authentication
     */
    @Override
    protected OAuth2Authentication remove(String code) {
        log.info("授权码过期,移除: [{}]", code);
        byte[] serializedKey = redisTemplate.getStringSerializer().serialize(CacheConstant.Strings.AUTHORIZATION_CODE_PREFIX + code);
        return redisTemplate.execute(conn -> {
            byte[] bytes = conn.get(Objects.requireNonNull(serializedKey));
            if (bytes != null) {
                conn.del(serializedKey);
            }
            return (OAuth2Authentication) redisTemplate.getValueSerializer().deserialize(bytes);
        }, true);
    }

}
